package site.wenneng.dev.controller;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.AllArgsConstructor;
import org.jetbrains.annotations.NotNull;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import site.wenneng.dev.common.util.CollectorUtils;
import site.wenneng.dev.dao.DefineSprintMapper;
import site.wenneng.dev.dao.DefineSprintStoryMapper;
import site.wenneng.dev.objs.po.DefineSprintPO;
import site.wenneng.dev.objs.po.DefineSprintStoryPO;
import site.wenneng.dev.objs.po.WorkingHoursPO;
import site.wenneng.dev.service.*;
import site.wenneng.dev.common.enumeration.DicEnum;
import site.wenneng.dev.objs.dto.common.Result;
import site.wenneng.dev.objs.dto.StoryDTO;
import site.wenneng.dev.objs.dto.StoryQueryDTO;
import site.wenneng.dev.objs.po.DefineRpPO;
import site.wenneng.dev.dao.DefineRpMapper;
import site.wenneng.dev.objs.bo.StoryLabelBO;
import site.wenneng.dev.objs.bo.StoryRemoteBO;
import site.wenneng.dev.objs.bo.StoryUserBO;
import site.wenneng.dev.objs.bo.TaskRemoteBO;

import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Stream;

import static java.util.stream.Collectors.*;

@RestController
@AllArgsConstructor
@RequestMapping("/rp")
public class RpManageController {

    private TaskService taskService;
    private StoryService storyService;
    private DefineRpMapper rpRepository;
    private DevUserService userService;
    private SimpleBizService simpleBizService;
    private DictionaryService dictionaryService;
    private WorkingHoursService workingHoursService;
    private DefineSprintMapper defineSprintMapper;
    private DefineSprintStoryMapper defineSprintStoryMapper;


    private static BigDecimal matchWorkload(String remark) {
        if (!ObjectUtils.isEmpty(remark)) {
            String template = "\\[合规基础设置组-工作量：(([0]|[1-9][0-9]*)([.]{1}[0-9]*){0,1})\\]";
            Matcher matcher = Pattern.compile(template).matcher(remark);
            if (matcher.find()) {
                return new BigDecimal(matcher.group(1));
            }
        }
        return BigDecimal.ZERO;
    }

    private static String matchAny(List<StoryLabelBO> labels, String match) {
        if (CollectionUtils.isEmpty(labels)) {
            return "";
        }
        return labels.stream()
                .filter(item -> item.getName().equals(match))
                .findAny().map(item -> "计划").orElse("");
    }

    @NotNull
    private static String toNameList(List<StoryUserBO> list) {
        if (CollectionUtils.isEmpty(list)) {
            return "";
        }
        return list.stream().map(StoryUserBO::getMemberName).collect(joining());
    }

    @GetMapping("/story")
    public Result<List<StoryDTO>> storyQuery(StoryQueryDTO dto) {
        // 获取RP信息
        List<DefineRpPO> allById = rpRepository.selectList(Wrappers.<DefineRpPO>lambdaQuery()
                .in(DefineRpPO::getId, dto.getRpIdList()));
        // 所属版本信息
        String versionList = allById.stream().map(DefineRpPO::getRpVersion).distinct().collect(joining(","));
        // 将RP进行分组
        Map<Boolean, List<DefineRpPO>> group = allById.stream()
                .collect(groupingBy(item -> item.getRpProjectId() == null));
        // 从效能平台查询需求信息
        List<String> userList = userService.getAllAssigneeId();
        List<StoryRemoteBO> storyRemoteList = group.entrySet().parallelStream().flatMap(item -> {
            if (item.getKey()) {
                List<Integer> labels = item.getValue().stream()
                        .flatMap(each -> Arrays.stream(each.getRpStoryLabels().split(",")))
                        .map(Integer::parseInt)
                        .collect(toList());
                return storyService.queryStoryByStoryLabel(labels, userList).stream();
            }
            List<Integer> projects = item.getValue().stream().map(DefineRpPO::getRpProjectId).collect(toList());
            return storyService.queryStoryByProject(projects, userList).stream();
        }).collect(toList());
        // 根据RP需求从效能平台查询任务
        List<String> storyNumberList = storyRemoteList.stream()
                .map(StoryRemoteBO::getNumber).distinct().collect(toList());
        List<TaskRemoteBO> taskRemoteBOList = taskService.queryByStoryNumber(storyNumberList, versionList);
        Map<String, List<TaskRemoteBO>> taskMap = taskService.getStoryTaskMap(taskRemoteBOList);

        List<StoryDTO> result = convertToDTO(storyRemoteList, taskMap, new HashMap<>());
        return Result.ok(result);
    }

    @GetMapping("/sprint")
    public Result<List<StoryDTO>> sprintStoryQuery(@RequestParam("sprintId") Integer sprintId) {
        // sprint详细信息
        DefineSprintPO sprintPO = defineSprintMapper.selectById(sprintId);
        // 根据冲刺填报的工时信息
        List<WorkingHoursPO> workingHoursList = findWorkingHoursListBySprint(sprintPO);
        // sprint维护的需求
        List<String> storyNumberList = findStoryBySprintId(sprintId);
        // sprint涉及的任务
        List<TaskRemoteBO> taskList = getSprintTaskList(sprintPO, storyNumberList, workingHoursList);
        // 需求任务关系
        Map<String, List<TaskRemoteBO>> storyTaskMap = taskService.getStoryTaskMap(taskList);
        // 需求工时关系
        Map<String, WorkingHoursPO> storyWorkingHours = getStoryWorkingHoursMap(workingHoursList, storyTaskMap);
        // 需求信息
        List<String> allStory = Stream.of(storyNumberList, storyTaskMap.keySet()).flatMap(Collection::stream).distinct().collect(toList());
        List<StoryRemoteBO> storyList = storyService.queryStoryByNumbers(allStory);
        // 结果
        List<StoryDTO> res = convertToDTO(storyList, storyTaskMap, storyWorkingHours);

        for (StoryDTO item : res) {
            if (storyNumberList.contains(item.getNumber())) {
                item.setSprintPlanFlag("已规划");
            } else if (item.getSelfUsedWorkload() != null) {
                item.setSprintPlanFlag("有投入");
            } else {
                item.setSprintPlanFlag("有任务");
            }
        }
        return Result.ok(res);
    }

    @GetMapping("/un-finish")
    public Result<List<StoryDTO>> unFinishStoryQuery() {
        List<TaskRemoteBO> task = taskService.queryUnfinishedTaskContainUncheck(userService.findAll());
        List<String> storyNumbers = task.stream().map(item -> {
            if (!StringUtils.isEmpty(item.getStoryNumbers())) {
                String[] split = item.getStoryNumbers().split(",");
                Arrays.sort(split);
                return split[0];
            }
            return null;
        }).filter(Objects::nonNull).distinct().collect(toList());
        List<StoryRemoteBO> storyList = storyService.queryStoryByNumbers(storyNumbers);
        List<TaskRemoteBO> taskList = taskService.queryByStoryNumber(storyNumbers);

        Map<String, List<TaskRemoteBO>> taskMap = taskService.getStoryTaskMap(taskList);
        List<StoryDTO> result = convertToDTO(storyList, taskMap, new HashMap<>());
        return Result.ok(result);
    }

    private List<WorkingHoursPO> findWorkingHoursListBySprint(DefineSprintPO sprintPO) {
        return workingHoursService.queryRecordDuring(sprintPO.getBeginDate(), sprintPO.getEndDate());
    }

    private Map<String, WorkingHoursPO> getStoryWorkingHoursMap(List<WorkingHoursPO> workingHoursList, Map<String, List<TaskRemoteBO>> storyTaskMap) {
        Map<String, String> taskStoryMap = new HashMap<>();
        for (Map.Entry<String, List<TaskRemoteBO>> entry : storyTaskMap.entrySet()) {
            for (TaskRemoteBO taskRemoteBO : entry.getValue()) {
                taskStoryMap.put(taskRemoteBO.getTaskNumber(), entry.getKey());
            }
        }
        Function<WorkingHoursPO, String> getStoryNum = item -> taskStoryMap.getOrDefault(item.getTaskId(), "");
        return workingHoursList.stream()
                .collect(groupingBy(getStoryNum, collectingAndThen(toList(), this::combMultiWorkingHours)));
    }

    @NotNull
    private List<StoryDTO> convertToDTO(List<StoryRemoteBO> storyRemoteList, Map<String, List<TaskRemoteBO>> taskMap, Map<String, WorkingHoursPO> workingHoursMap) {
        List<StoryDTO> result = new ArrayList<>();
        Set<String> finishedTaskStatusSet = dictionaryService.listLabelSet(DicEnum.FINISHED_TASK_STATUS);
        for (StoryRemoteBO remoteBO : storyRemoteList) {
            StoryDTO storyDTO = new StoryDTO();
            storyDTO.setId(remoteBO.getId());
            storyDTO.setNumber(remoteBO.getNumber());
            storyDTO.setName(remoteBO.getName());
            storyDTO.setStatus(remoteBO.getStatus());
            storyDTO.setStoryLabels(remoteBO.getStoryLabels());
            storyDTO.setSelfStoryHandlerList(toNameList(remoteBO.getStoryHandlerList()));
            storyDTO.setSelfStoryDesignerNameList(toNameList(remoteBO.getStoryDesignerList()));
            storyDTO.setSelfStoryReview(matchAny(remoteBO.getLabelList(), "需求评审-计划"));
            storyDTO.setSelfTaskReview(matchAny(remoteBO.getLabelList(), "概要设计-计划"));
            storyDTO.setSelfEstimateWorkload(matchWorkload(remoteBO.getRemark()));
            storyDTO.setSelfStatus(calcSelfStatus(taskMap.get(remoteBO.getNumber()), finishedTaskStatusSet));
            storyDTO.setSelfActualDesignNameList(calcDesignNameList(taskMap.get(remoteBO.getNumber())));
            storyDTO.setSelfActualDevelopNameList(calcDevelopNameList(taskMap.get(remoteBO.getNumber())));
            storyDTO.setSelfPriority(calcPriority(remoteBO));
//            storyDTO.setSelfVersionFinish(calcVersionFinish(taskMap, finishedTaskStatusSet, remoteBO));
            WorkingHoursPO workingHoursPO = workingHoursMap.get(remoteBO.getNumber());
            if (workingHoursPO != null) {
                storyDTO.setSelfUsedWorkload(workingHoursPO.getWorkingHours());
            }
            result.add(storyDTO);
        }
        return result;
    }

    private String calcVersionFinish(Map<String, List<TaskRemoteBO>> taskMap, Set<String> finishedTaskStatusSet, StoryRemoteBO remoteBO) {
        Map<String, List<TaskRemoteBO>> collect = taskMap.getOrDefault(remoteBO.getNumber(), Collections.emptyList()).stream()
                .filter(item -> item.getSprintVersion().endsWith("LS"))
                .collect(groupingBy(TaskRemoteBO::getSprintVersion));
        if (collect.isEmpty()) {
            return "";
        }
        Set<String> stringStream = collect.values().stream()
                .map(item -> calcSelfStatus(item, finishedTaskStatusSet)).collect(toSet());
        if (stringStream.contains("已完成")) {
            return "补丁已完成";
        } else if (stringStream.contains("联测中")) {
            return "补丁联测中";
        }
        return "补丁进行中";
    }

    private List<TaskRemoteBO> getSprintTaskList(DefineSprintPO sprintPO, List<String> storyNumberList, List<WorkingHoursPO> workingHoursList) {
        return Stream.of(1, 2, 3).parallel().map(item -> {
            switch (item) {
                case 1:// 有工时填报的任务
                    return taskService.queryByTaskNumbers(workingHoursList.stream().map(WorkingHoursPO::getTaskId).distinct().collect(toList()), "0");
                case 2:// 要求完成但未完成的任务
                    return taskService.queryUnFinishTaskByExpectDate(sprintPO.getBeginDate(), sprintPO.getEndDate());
                case 3:// 规划到冲刺里的需求的任务
                    return taskService.queryByStoryNumber(storyNumberList);
                default:// 其他情况不查询
                    return Collections.<TaskRemoteBO>emptyList();
            }
        }).flatMap(Collection::stream).collect(CollectorUtils.toDistinctList(TaskRemoteBO::getTaskNumber));
    }

    private WorkingHoursPO combMultiWorkingHours(List<WorkingHoursPO> list) {
        return list.stream().reduce(this::combWorkingHours).orElse(new WorkingHoursPO());
    }

    private WorkingHoursPO combWorkingHours(WorkingHoursPO o1, WorkingHoursPO o2) {
        o1.setProgress(o1.getProgress().max(o2.getProgress()));
        o1.setWorkingHours(o1.getWorkingHours().add(o2.getWorkingHours()));
        o1.setWorkingDate(o1.getWorkingDate().compareTo(o2.getWorkingDate()) > 0 ? o1.getWorkingDate() : o2.getWorkingDate());
        return o1;
    }

    @NotNull
    private List<String> findStoryBySprintId(Integer sprintId) {
        Wrapper<DefineSprintStoryPO> queryWrapper = Wrappers.<DefineSprintStoryPO>lambdaQuery()
                .eq(DefineSprintStoryPO::getSprintId, sprintId);
//                .eq(DefineSprintStoryPO::getPlanFlag, "1");
        return defineSprintStoryMapper.selectList(queryWrapper).stream()
                .map(DefineSprintStoryPO::getStoryNumber)
                .distinct().collect(toList());
    }

    private String calcPriority(StoryRemoteBO remoteBO) {
        if (remoteBO.getIsFeature()) {
            return "特性";
        }
        String[] arrays = new String[]{"必须包含", "O45要求包含", "天弘基金要求包含", "优先级1", "优先级2", "优先级3", "优先级4"};
        for (String name : arrays) {
            if (CollectionUtils.isEmpty(remoteBO.getLabelList())) {
                return "";
            }
            boolean match = remoteBO.getLabelList().stream()
                    .map(StoryLabelBO::getName)
                    .anyMatch(item -> Objects.equals(item, name));
            if (match) {
                return name;
            }
        }
        return "";
    }

    private String calcDesignNameList(List<TaskRemoteBO> taskRemoteList) {
        if (CollectionUtils.isEmpty(taskRemoteList)) {
            return "";
        }
        return taskRemoteList.stream()
                .filter(item -> Objects.equals(item.getTaskType(), 103))
                .map(TaskRemoteBO::getAssigneeName)
                .distinct().sorted()
                .collect(joining(","));
    }

    private String calcDevelopNameList(List<TaskRemoteBO> taskRemoteList) {
        if (CollectionUtils.isEmpty(taskRemoteList)) {
            return "";
        }
        return taskRemoteList.stream()
                .filter(item -> Objects.equals(item.getTaskType(), 2))
                .map(TaskRemoteBO::getAssigneeName)
                .distinct().sorted()
                .collect(joining(","));
    }

    private String calcSelfStatus(List<TaskRemoteBO> taskRemoteList, Set<String> finishedTaskStatusSet) {
        if (CollectionUtils.isEmpty(taskRemoteList)) {
            return "待分解";
        }

        List<TaskRemoteBO> devTask = taskRemoteList.stream()
                .filter(item -> item.getTaskType() != 103)
                .collect(toList());
        List<TaskRemoteBO> unFinishedTask = taskRemoteList.stream()
                .filter(item -> !finishedTaskStatusSet.contains(item.getSubStatusName()))
                .collect(toList());
        Set<TaskRemoteBO> unFinishedDesignTask = unFinishedTask.stream()
                .filter(item -> item.getTaskType() == 103)
                .collect(toSet());
        if (unFinishedDesignTask.size() != 0 || devTask.size() == 0) {
            return "设计中";
        }
        if (unFinishedTask.size() != 0) {
            boolean isTesting = unFinishedTask.stream().allMatch(item -> "待审核".equals(item.getSubStatusName()));
            return isTesting ? "联测中" : "开发中";
        }
        return "已完成";
    }
}
